// Copyright 2019-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import "MDCTextControlVerticalPositioningReferenceFilled.h"
#import "MDCTextControlVerticalPositioningReference.h"

static const CGFloat kMinPaddingAroundTextWhenNoFloatingLabel = 6.0f;
static const CGFloat kMaxPaddingAroundTextWhenNoFloatingLabel = 10.0f;
static const CGFloat kMinPaddingBetweenContainerTopAndFloatingLabel = 3.0f;
static const CGFloat kMaxPaddingBetweenContainerTopAndFloatingLabel = 10.0f;
static const CGFloat kMinPaddingBetweenFloatingLabelAndEditingText = 3.0f;
static const CGFloat kMaxPaddingBetweenFloatingLabelAndEditingText = 6.0f;
static const CGFloat kMinPaddingBetweenEditingTextAndContainerBottom = 6.0f;
static const CGFloat kMaxPaddingBetweenEditingTextAndContainerBottom = 10.0f;
static const CGFloat kMinPaddingAroundAssistiveLabels = 3.0f;
static const CGFloat kMaxPaddingAroundAssistiveLabels = 6.0f;

/**
 For slightly more context on what this class is doing look at
 MDCTextControlVerticalPositioningReferenceBase. It's very similar and has some comments. Maybe at
 some point all the positioning references should be refactored to share a superclass, because
 there's currently a lot of duplicated code among the three of them.
*/
@implementation MDCTextControlVerticalPositioningReferenceFilled

@synthesize paddingBetweenContainerTopAndFloatingLabel =
    _paddingBetweenContainerTopAndFloatingLabel;
@synthesize paddingBetweenContainerTopAndNormalLabel = _paddingBetweenContainerTopAndNormalLabel;
@synthesize paddingBetweenFloatingLabelAndEditingText = _paddingBetweenFloatingLabelAndEditingText;
@synthesize paddingBetweenEditingTextAndContainerBottom =
    _paddingBetweenEditingTextAndContainerBottom;
@synthesize paddingAboveAssistiveLabels = _paddingAboveAssistiveLabels;
@synthesize paddingBelowAssistiveLabels = _paddingBelowAssistiveLabels;
@synthesize containerHeightWithFloatingLabel = _containerHeightWithFloatingLabel;
@synthesize containerHeightWithoutFloatingLabel = _containerHeightWithoutFloatingLabel;
@synthesize paddingAroundTextWhenNoFloatingLabel = _paddingAroundTextWhenNoFloatingLabel;

- (instancetype)initWithFloatingFontLineHeight:(CGFloat)floatingLabelHeight
                          normalFontLineHeight:(CGFloat)normalFontLineHeight
                                 textRowHeight:(CGFloat)textRowHeight
                              numberOfTextRows:(CGFloat)numberOfTextRows
                                       density:(CGFloat)density
                      preferredContainerHeight:(CGFloat)preferredContainerHeight
                        isMultilineTextControl:(BOOL)isMultilineTextControl {
  self = [super init];
  if (self) {
    CGFloat clampedDensity = MDCTextControlClampDensity(density);

    _paddingBetweenContainerTopAndFloatingLabel = MDCTextControlPaddingValueWithMinimumPadding(
        kMinPaddingBetweenContainerTopAndFloatingLabel,
        kMaxPaddingBetweenContainerTopAndFloatingLabel, clampedDensity);

    _paddingBetweenFloatingLabelAndEditingText = MDCTextControlPaddingValueWithMinimumPadding(
        kMinPaddingBetweenFloatingLabelAndEditingText,
        kMaxPaddingBetweenFloatingLabelAndEditingText, clampedDensity);

    _paddingBetweenEditingTextAndContainerBottom = MDCTextControlPaddingValueWithMinimumPadding(
        kMinPaddingBetweenEditingTextAndContainerBottom,
        kMaxPaddingBetweenEditingTextAndContainerBottom, clampedDensity);

    _paddingAboveAssistiveLabels = MDCTextControlPaddingValueWithMinimumPadding(
        kMinPaddingAroundAssistiveLabels, kMaxPaddingAroundAssistiveLabels, clampedDensity);
    _paddingBelowAssistiveLabels = _paddingAboveAssistiveLabels;

    CGFloat defaultContainerHeightForFloatingLabel =
        MDCTextControlCalculateContainerHeightWithFloatingLabelHeight(
            floatingLabelHeight, textRowHeight, numberOfTextRows,
            _paddingBetweenContainerTopAndFloatingLabel, _paddingBetweenFloatingLabelAndEditingText,
            _paddingBetweenEditingTextAndContainerBottom);
    BOOL preferredContainerHeightIsValidForFloatingLabel =
        preferredContainerHeight > defaultContainerHeightForFloatingLabel;
    if (preferredContainerHeightIsValidForFloatingLabel) {
      _containerHeightWithFloatingLabel = preferredContainerHeight;
      BOOL shouldUpdatePaddingValuesToMeetMinimumHeight = !isMultilineTextControl;
      if (shouldUpdatePaddingValuesToMeetMinimumHeight) {
        CGFloat difference = preferredContainerHeight - defaultContainerHeightForFloatingLabel;
        CGFloat sumOfPaddingValues = _paddingBetweenContainerTopAndFloatingLabel +
                                     _paddingBetweenFloatingLabelAndEditingText +
                                     _paddingBetweenEditingTextAndContainerBottom;
        _paddingBetweenContainerTopAndFloatingLabel =
            _paddingBetweenContainerTopAndFloatingLabel +
            ((_paddingBetweenContainerTopAndFloatingLabel / sumOfPaddingValues) * difference);
        _paddingBetweenFloatingLabelAndEditingText =
            _paddingBetweenFloatingLabelAndEditingText +
            ((_paddingBetweenFloatingLabelAndEditingText / sumOfPaddingValues) * difference);
        _paddingBetweenEditingTextAndContainerBottom =
            _paddingBetweenEditingTextAndContainerBottom +
            ((_paddingBetweenEditingTextAndContainerBottom / sumOfPaddingValues) * difference);
      }
    } else {
      _containerHeightWithFloatingLabel = defaultContainerHeightForFloatingLabel;
    }

    _paddingAroundTextWhenNoFloatingLabel = MDCTextControlPaddingValueWithMinimumPadding(
        kMinPaddingAroundTextWhenNoFloatingLabel, kMaxPaddingAroundTextWhenNoFloatingLabel,
        clampedDensity);

    CGFloat defaultContainerHeightForNoFloatingLabel =
        MDCTextControlCalculateContainerHeightWhenNoFloatingLabelWithTextRowHeight(
            textRowHeight, numberOfTextRows, _paddingAroundTextWhenNoFloatingLabel);
    BOOL preferredContainerHeightIsValidForNoFloatingLabel =
        preferredContainerHeight > defaultContainerHeightForNoFloatingLabel;
    if (preferredContainerHeightIsValidForNoFloatingLabel) {
      _containerHeightWithoutFloatingLabel = preferredContainerHeight;
      BOOL shouldUpdatePaddingValuesToMeetMinimumHeight = !isMultilineTextControl;
      if (shouldUpdatePaddingValuesToMeetMinimumHeight) {
        CGFloat difference = preferredContainerHeight - defaultContainerHeightForNoFloatingLabel;
        CGFloat sumOfPaddingValues = _paddingAroundTextWhenNoFloatingLabel * 2.0f;
        _paddingAroundTextWhenNoFloatingLabel =
            _paddingAroundTextWhenNoFloatingLabel +
            ((_paddingAroundTextWhenNoFloatingLabel / sumOfPaddingValues) * difference);
      }
    } else {
      _containerHeightWithoutFloatingLabel = defaultContainerHeightForNoFloatingLabel;
    }

    CGFloat halfOfNormalFontLineHeight = (CGFloat)0.5 * normalFontLineHeight;
    if (isMultilineTextControl) {
      CGFloat heightWithOneRow = MDCTextControlCalculateContainerHeightWithFloatingLabelHeight(
          floatingLabelHeight, textRowHeight, 1, _paddingBetweenContainerTopAndFloatingLabel,
          _paddingBetweenFloatingLabelAndEditingText, _paddingBetweenEditingTextAndContainerBottom);
      CGFloat halfOfHeightWithOneRow = (CGFloat)0.5 * heightWithOneRow;
      _paddingBetweenContainerTopAndNormalLabel =
          halfOfHeightWithOneRow - halfOfNormalFontLineHeight;
    } else {
      CGFloat halfOfContainerHeight = (CGFloat)0.5 * _containerHeightWithFloatingLabel;
      _paddingBetweenContainerTopAndNormalLabel =
          halfOfContainerHeight - halfOfNormalFontLineHeight;
    }
  }
  return self;
}

- (CGFloat)paddingBetweenContainerTopAndFloatingLabel {
  return _paddingBetweenContainerTopAndFloatingLabel;
}

- (CGFloat)paddingBetweenContainerTopAndNormalLabel {
  return _paddingBetweenContainerTopAndNormalLabel;
}

- (CGFloat)paddingBetweenFloatingLabelAndEditingText {
  return _paddingBetweenFloatingLabelAndEditingText;
}

- (CGFloat)paddingBetweenEditingTextAndContainerBottom {
  return _paddingBetweenEditingTextAndContainerBottom;
}

- (CGFloat)paddingAboveAssistiveLabels {
  return _paddingAboveAssistiveLabels;
}

- (CGFloat)paddingBelowAssistiveLabels {
  return _paddingBelowAssistiveLabels;
}

- (CGFloat)containerHeightWithFloatingLabel {
  return _containerHeightWithFloatingLabel;
}

- (CGFloat)containerHeightWithoutFloatingLabel {
  return _containerHeightWithoutFloatingLabel;
}

- (CGFloat)paddingAroundTextWhenNoFloatingLabel {
  return _paddingAroundTextWhenNoFloatingLabel;
}

@end
